home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 7 / Night Owl Shareware (NOPV7)(Night Owl Publisher Inc.)(1992).bin / 038a / bash1_12.arj / BASH1-12.TAR / bash-1.12 / builtins / common.c < prev    next >
C/C++ Source or Header  |  1992-01-21  |  15KB  |  627 lines

  1. /* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
  2.  
  3.    This file is part of GNU Bash, the Bourne Again SHell.
  4.  
  5.    Bash is free software; you can redistribute it and/or modify it under
  6.    the terms of the GNU General Public License as published by the Free
  7.    Software Foundation; either version 1, or (at your option) any later
  8.    version.
  9.  
  10.    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  11.    WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13.    for more details.
  14.    
  15.    You should have received a copy of the GNU General Public License along
  16.    with Bash; see the file COPYING.  If not, write to the Free Software
  17.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  18.  
  19. #include <stdio.h>
  20. #include <sys/types.h>
  21. #if defined (HAVE_VPRINTF)
  22. #include <varargs.h>
  23. #endif /* VPRINTF */
  24.  
  25. #include "../shell.h"
  26. #include "../unwind_prot.h"
  27. #include "../maxpath.h"
  28. #include "../jobs.h"
  29. #include "../builtins.h"
  30. #include "../input.h"
  31. #include "hashcom.h"
  32.  
  33. void no_args (), remember_args (), parse_and_execute_cleanup ();
  34. extern int follow_symbolic_links, interactive;
  35.  
  36. /* Read a numeric arg for this_command_name, the name of the shell builtin
  37.    that wants it.  LIST is the word list that the arg is to come from. */
  38. int
  39. get_numeric_arg (list)
  40.      WORD_LIST *list;
  41. {
  42.   int count = 1;
  43.  
  44.   if (list)
  45.     {
  46.       if (sscanf (list->word->word, "%d", &count) != 1)
  47.     {
  48.       builtin_error ("bad non-numeric arg `%s'", list->word->word);
  49.       throw_to_top_level ();
  50.     }
  51.       no_args (list->next);
  52.     }
  53.   return (count);
  54. }
  55.  
  56. /* This is a lot like report_error (), but it is for shell builtins
  57.    instead of shell control structures, and it won't ever exit the
  58.    shell. */
  59. #if defined (HAVE_VPRINTF)
  60. /* VARARGS */
  61. builtin_error (va_alist)
  62.      va_dcl
  63. {
  64.   extern char *this_command_name;
  65.   char *format;
  66.   va_list args;
  67.  
  68.   if (this_command_name && *this_command_name)
  69.     fprintf (stderr, "%s: ", this_command_name);
  70.  
  71.   va_start (args);
  72.   format = va_arg (args, char *);
  73.   vfprintf (stderr, format, args);
  74.   va_end (args);
  75.   fprintf (stderr, "\n");
  76. }
  77.  
  78. #else /* Without VARARGS. */
  79. builtin_error (format, arg1, arg2, arg3, arg4, arg5)
  80.      char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
  81. {
  82.   extern char *this_command_name;
  83.  
  84.   if (this_command_name && *this_command_name)
  85.     fprintf (stderr, "%s: ", this_command_name);
  86.  
  87.   fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
  88.   fprintf (stderr, "\n");
  89.   fflush (stderr);
  90. }
  91. #endif /* HAVE_VPRINTF */
  92.  
  93. /* Remember LIST in $0 ... $9, and REST_OF_ARGS.  If DESTRUCTIVE is
  94.    non-zero, then discard whatever the existing arguments are, else
  95.    only discard the ones that are to be replaced. */
  96. void
  97. remember_args (list, destructive)
  98.      WORD_LIST *list;
  99.      int destructive;
  100. {
  101.   register int i;
  102.   extern WORD_LIST *copy_word_list ();
  103.  
  104.   for (i = 1; i < 10; i++)
  105.     {
  106.       if (destructive && dollar_vars[i])
  107.     {
  108.       free (dollar_vars[i]);
  109.       dollar_vars[i] = (char *)NULL;
  110.     }
  111.  
  112.       if (list)
  113.     {
  114.       if (!destructive && dollar_vars[i])
  115.         free (dollar_vars[i]);
  116.  
  117.       dollar_vars[i] = savestring (list->word->word);
  118.       list = list->next;
  119.     }
  120.     }
  121.  
  122.   /* If arguments remain, assign them to REST_OF_ARGS. */
  123.   if (!list)
  124.     {
  125.       dispose_words (rest_of_args);
  126.       rest_of_args = NULL;
  127.     }
  128.   else
  129.     {
  130.       rest_of_args = (WORD_LIST *)copy_word_list (list);
  131.     }
  132. }
  133.  
  134. /* Return if LIST is NULL else barf and jump to top_level. */
  135. void
  136. no_args (list)
  137.      WORD_LIST *list;
  138. {
  139.   if (list)
  140.     {
  141.       builtin_error ("extra arguments");
  142.       longjmp (top_level, DISCARD);
  143.     }
  144. }
  145.  
  146. /* Return the octal number parsed from STRING, or -1 to indicate
  147.    that the string contained a bad number. */
  148. int
  149. read_octal (string)
  150.      char *string;
  151. {
  152.   int result = 0;
  153.   int digits = 0;
  154.  
  155.   while (*string && *string >= '0' && *string < '8')
  156.     {
  157.       digits++;
  158.       result = (result * 8) + *string++ - '0';
  159.     }
  160.  
  161.   if (!digits || result > 0777 || *string)
  162.     result = -1;
  163.  
  164.   return (result);
  165. }
  166.  
  167. /* Temporary static. */
  168. char *dotted_filename = (char *)NULL;
  169.  
  170. /* Return the full pathname that FILENAME hashes to.  If FILENAME
  171.    is hashed, but data->check_dot is non-zero, check ./FILENAME
  172.    and return that if it is executable. */
  173. char *
  174. find_hashed_filename (filename)
  175.      char *filename;
  176. {
  177.   extern HASH_TABLE *hashed_filenames;
  178.   extern int hashing_disabled;
  179.   register BUCKET_CONTENTS *item;
  180.  
  181.   if (hashing_disabled)
  182.     return ((char *)NULL);
  183.  
  184.   item = find_hash_item (filename, hashed_filenames);
  185.  
  186.   if (item)
  187.     {
  188.       /* If this filename is hashed, but `.' comes before it in the path,
  189.      then see if `./filename' is an executable. */
  190.       if (pathdata(item)->check_dot)
  191.     {
  192.       if (dotted_filename)
  193.         free (dotted_filename);
  194.  
  195.       dotted_filename = (char *)xmalloc (3 + strlen (filename));
  196.       strcpy (dotted_filename, "./");
  197.       strcat (dotted_filename, filename);
  198.  
  199.       if (executable_file (dotted_filename))
  200.         return (dotted_filename);
  201.  
  202.       /* Watch out.  If this file was hashed to "./filename", and
  203.          "./filename" is not executable, then return NULL. */
  204.  
  205.       /* Since we already know "./filename" is not executable, what
  206.          we're really interested in is whether or not the `path'
  207.          portion of the hashed filename is equivalent to the current
  208.          directory, but only if it starts with a `.'.  (This catches
  209.          ./. and so on.)  same_file () is in execute_cmd.c; it tests
  210.          general Unix file equivalence -- same device and inode. */
  211.       {
  212.         char *path = pathdata (item)->path;
  213.  
  214.         if (*path == '.')
  215.           {
  216.         int same = 0;
  217.         char *rindex (), *tail;
  218.  
  219.         tail = rindex (path, '/');
  220.  
  221.         if (tail)
  222.           {
  223.             *tail = '\0';
  224.             same = same_file
  225.               (".", path, (struct stat *)NULL, (struct stat *)NULL);
  226.             *tail = '/';
  227.           }
  228.         if (same)
  229.           return ((char *)NULL);
  230.           }
  231.       }
  232.     }
  233.       return (pathdata (item)->path);
  234.     }
  235.   else
  236.     return ((char *)NULL);
  237. }
  238.  
  239. /* **************************************************************** */
  240. /*                                    */
  241. /*            Pushing and Popping a Context            */
  242. /*                                    */
  243. /* **************************************************************** */
  244.  
  245. WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
  246. int dollar_arg_stack_slots = 0;
  247. int dollar_arg_stack_index = 0;
  248.  
  249. void push_dollar_vars (), pop_dollar_vars ();
  250.  
  251. void
  252. push_context ()
  253. {
  254.   extern int variable_context;
  255.  
  256.   push_dollar_vars ();
  257.   variable_context++;
  258. }
  259.  
  260. void
  261. pop_context ()
  262. {
  263.   extern int variable_context;
  264.  
  265.   pop_dollar_vars ();
  266.   kill_all_local_variables ();
  267.   variable_context--;
  268. }
  269.  
  270. /* Save the existing positional parameters on a stack. */
  271. void
  272. push_dollar_vars ()
  273. {
  274.   extern WORD_LIST *list_rest_of_args ();
  275.  
  276.   if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
  277.     {
  278.       if (!dollar_arg_stack)
  279.     {
  280.       dollar_arg_stack =
  281.         (WORD_LIST **)xrealloc (dollar_arg_stack,
  282.                     (dollar_arg_stack_slots += 10)
  283.                     * sizeof (WORD_LIST **));
  284.     }
  285.     }
  286.   dollar_arg_stack[dollar_arg_stack_index] = list_rest_of_args ();
  287.   dollar_arg_stack[++dollar_arg_stack_index] = (WORD_LIST *)NULL;
  288. }
  289.  
  290. /* Restore the positional parameters from our stack. */
  291. void
  292. pop_dollar_vars ()
  293. {
  294.   if (!dollar_arg_stack || !dollar_arg_stack_index)
  295.     return;
  296.  
  297.   remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
  298.   dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
  299.   dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
  300. }
  301.  
  302. /* Function called when one of the builtin commands detects a bad
  303.    option. */
  304. bad_option (s)
  305.      char *s;
  306. {
  307.   builtin_error ("unknown option: %s", s);
  308. }
  309.  
  310. /* Return a consed string which is the current working directory.
  311.    FOR_WHOM is the name of the caller for error printing.  */
  312. char *the_current_working_directory = (char *)NULL;
  313.  
  314. char *
  315. get_working_directory (for_whom)
  316.      char *for_whom;
  317. {
  318.   if (!follow_symbolic_links)
  319.     {
  320.       if (the_current_working_directory)
  321.     free (the_current_working_directory);
  322.  
  323.       the_current_working_directory = (char *)NULL;
  324.     }
  325.  
  326.   if (!the_current_working_directory)
  327.     {
  328.       char *directory, *getwd ();
  329.  
  330.       the_current_working_directory = (char *)xmalloc (MAXPATHLEN);
  331.       directory = getwd (the_current_working_directory);
  332.       if (!directory)
  333.     {
  334.       fprintf (stderr, "%s: %s\n\r",
  335.            for_whom, the_current_working_directory);
  336.       free (the_current_working_directory);
  337.       the_current_working_directory = (char *)NULL;
  338.       return (char *)NULL;
  339.     }
  340.     }
  341.  
  342.   return (savestring (the_current_working_directory));
  343. }
  344.  
  345. #if defined (JOB_CONTROL)
  346. /* Return the job spec found in LIST. */
  347. get_job_spec (list)
  348.      WORD_LIST *list;
  349. {
  350.   register char *word;
  351.   int job = NO_JOB;
  352.   int substring = 0;
  353.  
  354.   if (!list)
  355.     return (current_job);
  356.  
  357.   word = list->word->word;
  358.  
  359.   if (!*word)
  360.     return (current_job);
  361.  
  362.   if (*word == '%')
  363.     word++;
  364.  
  365.   if (digit (*word) && (sscanf (word, "%d", &job) == 1))
  366.     return (job - 1);
  367.  
  368.   switch (*word)
  369.     {
  370.     case 0:
  371.     case '%':
  372.     case '+':
  373.       return (current_job);
  374.  
  375.     case '-':
  376.       return (previous_job);
  377.  
  378.     case '?':            /* Substring search requested. */
  379.       substring++;
  380.       word++;
  381.       goto find_string;
  382.  
  383.     default:
  384.     find_string:
  385.       {
  386.     register int i, wl = strlen (word);
  387.     for (i = 0; i < job_slots; i++)
  388.       {
  389.         if (jobs[i])
  390.           {
  391.         register PROCESS *p = jobs[i]->pipe;
  392.         extern char *strindex ();
  393.         do
  394.           {
  395.             if ((substring && strindex (p->command, word)) ||
  396.             (strncmp (p->command, word, wl) == 0))
  397.               if (job != NO_JOB)
  398.             {
  399.               builtin_error ("ambigious job spec: %s", word);
  400.               return (DUP_JOB);
  401.             }
  402.               else
  403.             job = i;
  404.  
  405.             p = p->next;
  406.           }
  407.         while (p != jobs[i]->pipe);
  408.           }
  409.       }
  410.     return (job);
  411.       }
  412.     }
  413. }
  414. #endif /* JOB_CONTROL */
  415.  
  416. /* The command name of the currently running function. */
  417. extern char *this_command_name;
  418.  
  419. int parse_and_execute_level = 0;
  420.  
  421. /* How to force parse_and_execute () to clean up after itself. */
  422. void
  423. parse_and_execute_cleanup ()
  424. {
  425.   run_unwind_frame ("parse_and_execute_top");
  426. }
  427.  
  428. /* Parse and execute the commands in STRING.  Returns whatever
  429.    execute_command () returns.  This frees STRING. */
  430. int
  431. parse_and_execute (string, from_file)
  432.      char *string;
  433.      char *from_file;
  434. {
  435.   extern int remember_on_history;
  436.   extern int history_expansion_inhibited;
  437.   extern int indirection_level;
  438.   extern int builtin_pipe_in, builtin_pipe_out;
  439.   extern COMMAND *global_command;
  440.   extern char *indirection_level_string ();
  441.   extern int pop_stream (), free ();
  442.  
  443.   int last_result = EXECUTION_SUCCESS;
  444.   int code, jump_to_top_level = 0;
  445.   char *orig_string = string;
  446.  
  447.   /* Unwind protect this invocation of parse_and_execute (). */
  448.   begin_unwind_frame ("parse_and_execute_top");
  449.     unwind_protect_int (parse_and_execute_level);
  450.     unwind_protect_jmp_buf (top_level);
  451.     unwind_protect_int (indirection_level);
  452.     unwind_protect_int (interactive);
  453.     unwind_protect_int (remember_on_history);
  454.     unwind_protect_int (history_expansion_inhibited);
  455.     add_unwind_protect (pop_stream, (char *)NULL);
  456.     if (orig_string)
  457.       add_unwind_protect (free, orig_string);
  458.   end_unwind_frame ();
  459.  
  460.   parse_and_execute_level++;
  461.   push_stream ();
  462.   interactive = 0;
  463.   indirection_level++;
  464.  
  465.   /* We don't remember text read by the shell this way on
  466.      the history list, and we don't use !$ in shell scripts. */
  467.   remember_on_history = 0;
  468.   history_expansion_inhibited = 1;
  469.  
  470.   with_input_from_string (string, from_file);
  471.   {
  472.     COMMAND *command;
  473.  
  474.     while (*(bash_input.location.string))
  475.       {
  476.     if (interrupt_state)
  477.       {
  478.         last_result = EXECUTION_FAILURE;
  479.         break;
  480.       }
  481.  
  482.     /* Provide a location for functions which `longjmp (top_level)' to
  483.        jump to.  This prevents errors in substitution from restarting
  484.        the reader loop directly, for example. */
  485.     code = setjmp (top_level);
  486.  
  487.     if (code)
  488.       {
  489.         switch (code)
  490.           {
  491.           case FORCE_EOF:
  492.           case EXITPROG:
  493.         run_unwind_frame ("pe_dispose");
  494.         /* Remember to call longjmp (top_level) after the old
  495.            value for it is restored. */
  496.         jump_to_top_level = 1;
  497.         goto out;
  498.  
  499.           case DISCARD:
  500.         run_unwind_frame ("pe_dispose");
  501.         continue;
  502.  
  503.           default:
  504.         programming_error ("bad jump to top_level: %d", code);
  505.         break;
  506.           }
  507.       }
  508.       
  509.     if (parse_command () == 0)
  510.       {
  511.         if ((command = global_command) != (COMMAND *)NULL)
  512.           {
  513.         extern struct fd_bitmap *new_fd_bitmap ();
  514.         extern void dispose_fd_bitmap ();
  515.         struct fd_bitmap *bitmap;
  516.  
  517.         bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
  518.         begin_unwind_frame ("pe_dispose");
  519.         add_unwind_protect (dispose_fd_bitmap, bitmap);
  520.  
  521.         global_command = (COMMAND *)NULL;
  522.  
  523.         if (builtin_pipe_in != NO_PIPE)
  524.           bitmap->bitmap[builtin_pipe_in] = 1;
  525.  
  526.         if (builtin_pipe_out != NO_PIPE)
  527.           bitmap->bitmap[builtin_pipe_out] = 1;
  528.  
  529.         last_result =
  530.           execute_command_internal
  531.             (command, 0, NO_PIPE, NO_PIPE, bitmap);
  532.  
  533.         dispose_command (command);
  534.         run_unwind_frame ("pe_dispose");
  535.           }
  536.       }
  537.     else
  538.       {
  539.         last_result = EXECUTION_FAILURE;
  540.  
  541.         /* Since we are shell compatible, syntax errors in a script
  542.            abort the execution of the script.  Right? */
  543.         break;
  544.       }
  545.       }
  546.   }
  547.  
  548.  out:
  549.  
  550.   run_unwind_frame ("parse_and_execute_top");
  551.  
  552.   if (interrupt_state && parse_and_execute_level == 0)
  553.     throw_to_top_level ();
  554.  
  555.   if (jump_to_top_level)
  556.     longjmp (top_level, code);
  557.  
  558.   return (last_result);
  559. }
  560.  
  561. /* Return the address of the builtin named NAME.
  562.    DISABLED_OKAY means find it even if the builtin is disabled. */
  563. Function *
  564. builtin_address_internal (name, disabled_okay)
  565.      char *name;
  566.      int disabled_okay;
  567. {
  568.   int hi, lo, mid, j;
  569.  
  570.   hi = num_shell_builtins - 1;
  571.   lo = 0;
  572.  
  573.   while (lo <= hi)
  574.     {
  575.       mid = (lo + hi) / 2;
  576.       j = strcmp (shell_builtins[mid].name, name);
  577.  
  578.       if (j == 0)
  579.     {
  580.       if (shell_builtins[mid].function &&
  581.           (shell_builtins[mid].enabled || disabled_okay))
  582.         return (shell_builtins[mid].function);
  583.       else
  584.         return ((Function *)NULL);
  585.     }
  586.       if (j > 0)
  587.     hi = mid - 1;
  588.       else
  589.     lo = mid + 1;
  590.     }
  591.   return ((Function *)NULL);
  592. }
  593.  
  594. /* Perform a binary search and return the address of the builtin function
  595.    whose name is NAME.  If the function couldn't be found, or the builtin
  596.    is disabled or has no function associated with it, return NULL. */
  597. Function *
  598. find_shell_builtin (name)
  599.     char *name;
  600. {
  601.   return (builtin_address_internal (name, 0));
  602. }
  603.  
  604. /* Return the address of builtin with NAME, irregardless of its state of
  605.    enableness. */
  606. Function *
  607. builtin_address (name)
  608.      char *name;
  609. {
  610.   return (builtin_address_internal (name, 1));
  611. }
  612.  
  613. static int
  614. shell_builtin_compare (sbp1, sbp2)
  615.      struct builtin *sbp1, *sbp2;
  616. {
  617.   return (strcmp (sbp1->name, sbp2->name));
  618. }
  619.  
  620. /* Sort the table of shell builtins so that the binary search will work
  621.    in find_shell_builtin. */
  622. initialize_shell_builtins ()
  623. {
  624.   qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
  625.     shell_builtin_compare);
  626. }
  627.